<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
<title>Node.js tutorial: Optimizing code performance using async - The Node Beginner Blog</title>

<meta property="og:site_name" content="The Node Beginner Blog">
<meta property="og:locale" content="en_US">
<meta property="og:type" content="article">
<meta property="fb:profile_id" content="1144782312">
<meta property="fb:app_id" content="150404395523663">
<meta property="article:author" content="https://www.facebook.com/NodeBeginner/">
<meta property="article:tag" content="Node.js">
<meta property="article:tag" content="JavaScript">
<meta property="article:tag" content="Programming">
<meta property="article:tag" content="Software">
<meta property="article:tag" content="Tutorial">
<meta property="fb:pages" content="319963981788483">
<meta property="og:url" content="https://www.nodebeginner.org/blog/post/nodejs-tutorial-optimizing-code-performance-using-async/">
<meta property="og:title" content="Node.js tutorial: Optimizing code performance using async">
<meta property="og:image" content='https://www.nodebeginner.org/blog/images/nodejs-tutorial-optimizing-code-performance-using-async-new.png'>
<meta property="og:image:secure_url" content='https://www.nodebeginner.org/blog/images/nodejs-tutorial-optimizing-code-performance-using-async-new.png'>
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:description" content='Writing asynchronous code that performs fast AND is beautifully structured can be complicated, but this comprehensive post shows how to achieve it.'>


<link rel="stylesheet" href="https://www.nodebeginner.org/blog/css/slim.css">
<link rel="stylesheet" href="https://www.nodebeginner.org/blog/css/highlight.min.css">


<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/apple-touch-icon-144-precomposed.png">
<link rel="shortcut icon" href="/favicon.ico">


<link href="" rel="alternate" type="application/rss+xml" title="The Node Beginner Blog" />

</head>

<body>
  <div class="container">
    <div class="header">
  <h1 class="site-title"><a href="https://www.nodebeginner.org/blog/">The Node Beginner Blog</a></h1>
  <p class="site-tagline">Your regularly updated tutorial resource for all things Node.js.</p>

  
</div>
    <div class="content">
      <div class="posts">
        <div class="post">
          <h2 class="post-title"><a href="https://www.nodebeginner.org/blog/post/nodejs-tutorial-optimizing-code-performance-using-async/">Node.js tutorial: Optimizing code performance using async</a></h2>
          <span class="post-date">Jun 6, 2017 </span>
          <div class="post-content">
            <p>The more complex your Node.js applications become, the more you need to think about the so-called
<em>control-flow</em> of your code. Especially when the need arises to optimize operations in terms of
efficiency and performance by introducing background operations and parallelity, the code can
quickly become a mess. Let&rsquo;s see what that means and what we can do about it. </p>

<p>Writing or using functions or methods in your Node.js code that are executed one after the
other gets you a long way in your applications.</p>

<p>Sometimes, those functions are simple synchronous steps:</p>

<pre><code>console.log('Starting calculation...');
var result = 5 + 4;
console.log('The result is', result);
</code></pre>

<p>Often, callbacks are used when operations are executed in the background and jump
back into our code&rsquo;s control flow asynchronously at a later point in time:</p>

<pre><code>console.log('Starting calculation...');
startExpensiveCalculation(5, 4, function(err, result) {
  if (!err) {
    console.log('The result is', result);
  }
});
</code></pre>

<p>If those asynchronous background operations bring forth a more complex callback
behaviour, they might be implemented as an event emitter:</p>

<pre><code>console.log('Starting calculation...');

calculation = Calculator.start(5, 4);

calculation.on('error', function(err) {
  console.log('An error occured:', err);
});

calculation.on('interim result', function(result) {
  console.log('Received interim result:', result);
});

calculation.on('done', function(result) {
  console.log('Received final result:', result);
});
</code></pre>

<p>Handling expensive operations asynchronously in the background, especially if they are
IO-bound, is an important key to <a href="https://www.nodebeginner.org/#passing-functions-around">making Node.js applications perform efficiently</a> -
reading a large file or writing a lot of records to a database will always be a costly
procedure, but handling it asynchronously at least ensures that the other parts of our
application won&rsquo;t be blocked while that procedure is going on.</p>

<p>Nevertheless, there is often potential for optimization within our own code and its
control flow.</p>

<h2 id="executing-expensive-asynchronous-background-tasks-in-parallel">Executing expensive asynchronous background tasks in parallel</h2>

<p>Let&rsquo;s consider an example where our application queries several different remote web
services, presenting the retrieved data on the console.</p>

<p>We are not going to query real remote web services, instead we will
<a class="internal" href="https://www.nodebeginner.org/#a-basic-http-server">write a very simple Node.js HTTP server</a>
that will serve as a dummy web service.
Our web server doesn&rsquo;t really do anything significant, and therefore we will make it react to
requests a bit slower than neccessary, in order to simulate a real web service that
has a certain workload - as you will see, this makes it easier for us to show the
performance gain in our own code optimizations.</p>

<p>Please create a new project folder and create a file <em>server.js</em> with the following
content:</p>

<pre><code>'use strict';

var http = require('http');
var url = require('url');
var querystring = require('querystring');

http.createServer(function(request, response) {

  var pathname = url.parse(request.url).pathname;
  var query = url.parse(request.url).query;
  var id = querystring.parse(query)['id'];

  var result = {
    'pathname': pathname,
    'id': id,
    'value': Math.floor(Math.random() * 100)
  };

  setTimeout(function() {
    response.writeHead(200, {&quot;Content-Type&quot;: &quot;application/json&quot;});
    response.end(JSON.stringify(result));
  }, 2000 + Math.floor(Math.random() * 1000));

}).listen(
  8080,
  function() {
    console.log('Echo Server listening on port 8080');
  }
);
</code></pre>

<p>This gives us a very simple &ldquo;echo&rdquo; server - if we request the URL
h&#8291;ttp://localhost:8080/getUser?id=4, we receive
<code>{&quot;pathname&quot;:&quot;/getUser&quot;,&quot;id&quot;:&quot;4&quot;,&quot;value&quot;:67}</code> as the response. This is good enough to
give us the simulation of a <a class="internal" href="https://www.nodebeginner.org/">remote webservice API</a> to play around with.</p>

<p>But alas, it&rsquo;s a slow webservice! Someone didn&rsquo;t do his optimization homework, and we
now have to deal with an API where every response takes between 2 to 3 seconds
(this is simulated with the <em>setTimeout</em> construct on lines 19-22).</p>

<p>This allows to show how different request patterns will result in different runtime
characteristics.</p>

<p>We will now <a class="internal" href="https://www.nodebeginner.org/">write a Node.js client</a> for this webserver. This client will make two
consecutive requests to the server, and print the output for both requests on the
command line:</p>

<pre><code>'use strict';

var request = require('request');

request.get(
  'http://localhost:8080/getUserName?id=1234',
  function(err, res, body) {
    var result = JSON.parse(body);
    var name = result.value;

    request.get(
      'http://localhost:8080/getUserStatus?id=1234',
      function(err, res, body) {
        var result = JSON.parse(body);
        var status = result.value;

        console.log('The status of user', name, 'is', status);
  });

});
</code></pre>

<p>Save this in a file called <em>client.js</em>. Also, you need to install the <em>request</em> module
via <code>npm install request@2.79.0</code>.</p>

<p>This is probably the most straight-forward solution. We start the first request, wait
for it to finish, print the result, then start the second request, wait for it to
finish, and print that result, too.</p>

<p>How long does that take? Let&rsquo;s see:</p>

<pre><code>$ time node client.js
The status of user 62 is 68

real  0m5.810s
user  0m0.172s
sys   0m0.033s
</code></pre>

<p>Don&rsquo;t forget to start the server via <code>node server.js</code> beforehand!</p>

<p>Not surprisingly, it takes around 5-6 seconds, because we only start the
second request after the first request has been completed, and each request takes
around 2-3 seconds.</p>

<p>We can&rsquo;t do anything about the terribly slow remote webservice, but our own code isn&rsquo;t
exactly optimal either. Our two requests don&rsquo;t inherently depend on each other, and
yet, we are executing them serially.</p>

<p>Of course starting these requests in parallel is simple, because both are asynchronous
operations:</p>

<pre><code>'use strict';

var request = require('request');

var name, status;

request.get(
  'http://localhost:8080/getUserName?id=1234',
  function(err, res, body) {
    var result = JSON.parse(body);
    name = result.value;
});

request.get(
  'http://localhost:8080/getUserStatus?id=1234',
  function(err, res, body) {
    var result = JSON.parse(body);
    status = result.value;
});

console.log('The status of user', name, 'is', status);
</code></pre>

<p>No, wait, sorry! That&rsquo;s not going to work - <em>console.log</em> will execute within the
first event loop iteration while the request callbacks are triggered in later
iterations. Mh, how about&hellip;</p>

<pre><code>'use strict';

var request = require('request');

var name, status;

request.get(
  'http://localhost:8080/getUserName?id=1234',
  function(err, res, body) {
    var result = JSON.parse(body);
    name = result.value;
});

request.get(
  'http://localhost:8080/getUserStatus?id=1234',
  function(err, res, body) {
    var result = JSON.parse(body);
    status = result.value;

    console.log('The status of user', name, 'is', status);
});
</code></pre>

<p>No, that&rsquo;s not good either: We <em>start</em> both request in parallel, but we have no
guarantee that they will finish at the same time. We risk printing</p>

<pre><code>The status of user undefined is 75
</code></pre>

<p>if the second request finishes earlier than the first. Well, looks like we need some
additional code to synchronize our finished calls. How about this:</p>

<pre><code>'use strict';

var request = require('request');

var name, status;
var firstHasFinished, secondHasFinished = false;

request.get(
  'http://localhost:8080/getUserName?id=1234',
  function(err, res, body) {
    var result = JSON.parse(body);
    name = result.value;
    markFinished('first');
});

request.get(
  'http://localhost:8080/getUserStatus?id=1234',
  function(err, res, body) {
    var result = JSON.parse(body);
    status = result.value;
    markFinished('second');
});

function markFinished(step) {
  if (step == 'first') {
    firstHasFinished = true;
  }

  if (step == 'second') {
    secondHasFinished = true;
  }

  if (firstHasFinished &amp;&amp; secondHasFinished) {
    console.log('The status of user', name, 'is', status);
  }
}
</code></pre>

<p>Seriously now - that&rsquo;s not even funny! What if we need to synchronize dozens or
hundreds of operations? We could use an array where we store the state of each
operation&hellip; no, this whole thing doesn&rsquo;t feel right.</p>

<p><em>async</em> to the rescue, I say!</p>

<p><em>async</em> is a clever little module that makes managing complex control flows in our
code a breeze.</p>

<p>After <a href="/blog/post/nodejs-tutorial-what-are-node.js-modules/">installing the module</a> via <code>npm install async@2.1.4</code>, we can write our client like
this:</p>

<pre><code>'use strict';

var request = require('request');
var async = require('async');

var name, status;

var getUsername = function(callback) {
  request.get(
    'http://localhost:8080/getUserName?id=1234',
    function(err, res, body) {
      var result = JSON.parse(body);
      callback(err, result.value);
    });
};

var getUserStatus = function(callback) {
  request.get(
    'http://localhost:8080/getUserStatus?id=1234',
    function (err, res, body) {
      var result = JSON.parse(body);
      callback(err, result.value);
    });
};

async.parallel([getUsername, getUserStatus], function(err, results) {
  console.log('The status of user', results[0], 'is', results[1]);
});
</code></pre>

<p>Let&rsquo;s analyze what we are doing here.</p>

<p>On line 4, we load the async library. We then wrap our requests into named functions.
These functions will be called with a <em>callback</em> parameter. Inside our functions, we
trigger this callback when our operation has finished - in this case, when the
requests have been answered.</p>

<p>We call the callbacks with two parameters: an <em>error</em> object (which is <em>null</em> if no
errors occured), and the result value.</p>

<p>The orchestration happens on lines 26-28. We use the <em>parallel</em> method of the <em>async</em>
object and pass an array of all the functions we want to run in parallel.
Additionally, we pass a callback function which expect two parameters, <em>err</em> and
<em>results</em>.</p>

<p><em>async.parallel</em> will trigger this callback as soon as the slowest of the parallel
operations has finished (and called its callback), or as soon as one of the operations
triggers its callback with an error.</p>

<p>Let&rsquo;s see what this does to the total runtime of our script:</p>

<pre><code>$ time node client.js
The status of user 95 is 54

real   0m3.176s
user   0m0.240s
sys    0m0.044s
</code></pre>

<p>As one would expect, the total runtime of our own code matches the runtime of one
request because both requests are started in parallel and will finish roughly at the
same time.</p>

<h2 id="optimizing-code-structure-with-async">Optimizing code structure with <em>async</em></h2>

<p><em>async</em> offers several other mechanisms for <a class="internal" href="https://www.nodebeginner.org/">managing the control flow</a> of our code.
These are interesting even if our concern isn&rsquo;t performance optimization. Let&rsquo;s
investigate them.</p>

<p>For these cases, let&rsquo;s remove the artificial slowness from our <a href="Node.js API server">https://www.nodebeginner.org/#a-basic-http-server</a>
by removing the <em>setTimeout</em> operation on line 19 and 22, making the server respond
immediately:</p>

<pre><code>'use strict';

var http = require('http');
var url = require('url');
var querystring = require('querystring');

http.createServer(function(request, response) {

  var pathname = url.parse(request.url).pathname;
  var query = url.parse(request.url).query;
  var id = querystring.parse(query)['id'];

  var result = {
    'pathname': pathname,
    'id': id,
    'value': Math.floor(Math.random() * 100)
  };

  response.writeHead(200, {&quot;Content-Type&quot;: &quot;application/json&quot;});
  response.end(JSON.stringify(result));

}).listen(
  8080,
  function() {
    console.log('Echo Server listening on port 8080');
  }
);
</code></pre>

<p>Sometimes we want to run operations in series. This is of course possible by putting
method calls into the callback functions of previous method calls, but the code
quickly becomes ugly if you do this with a lot of methods:</p>

<pre><code>'use strict';

var request = require('request');

var url = 'http://localhost:8080/';

request.get(url + 'getUserName?id=1234', function(err, res, body) {
  console.log('Name:', JSON.parse(body).value);

  request.get(url + 'getUserStatus?id=1234', function(err, res, body) {
    console.log('Status:', JSON.parse(body).value);

    request.get(url + 'getUserCountry?id=1234', function(err, res, body) {
      console.log('Country:', JSON.parse(body).value);

      request.get(url + 'getUserAge?id=1234', function(err, res, body) {
        console.log('Age:', JSON.parse(body).value);
      });

    });

  });

});
</code></pre>

<p>This is already starting to look messy, and we haven&rsquo;t even added any notable
&ldquo;business logic&rdquo; to our code.</p>

<p>Note how our code is intended another level with every method call, creating the
so-called &ldquo;boomerang pattern&rdquo; that is typical for multi-level nested callback control
flows.</p>

<p>We can use <em>async.series</em> to achieve the same control flow with much cleaner code:</p>

<pre><code>'use strict';

var request = require('request');
var async = require('async');

var url = 'http://localhost:8080/';

async.series([

  function(callback) {
    request.get(url + 'getUserName?id=1234', function(err, res, body) {
      console.log('Name:', JSON.parse(body).value);
      callback(null);
    });
  },

  function(callback) {
    request.get(url + 'getUserStatus?id=1234', function(err, res, body) {
      console.log('Status:', JSON.parse(body).value);
      callback(null);
    });
  },

  function(callback) {
    request.get(url + 'getUserCountry?id=1234', function(err, res, body) {
      console.log('Country:', JSON.parse(body).value);
      callback(null);
    });
  },

  function(callback) {
    request.get(url + 'getUserAge?id=1234', function(err, res, body) {
      console.log('Age:', JSON.parse(body).value);
      callback(null);
    });
  }

]);
</code></pre>

<p>Just as with <em>async.parallel</em>, we can use <em>async.series</em> to collect the results of
each step and do something with them once all steps have finished. This is again
achieved by passing the result of each step to the callback each step triggers, and
by providing a callback function to the <em>async.series</em> call which will receive an
array of all results:</p>

<pre><code>'use strict';

var request = require('request');
var async = require('async');

var url = 'http://localhost:8080/';

async.series([

  function(callback) {
    request.get(url + 'getUserName?id=1234', function(err, res, body) {
      callback(null, 'Name: ' + JSON.parse(body).value);
    });
  },

  function(callback) {
    request.get(url + 'getUserStatus?id=1234', function(err, res, body) {
      callback(null, 'Status: ' + JSON.parse(body).value);
    });
  },

  function(callback) {
    request.get(url + 'getUserCountry?id=1234', function(err, res, body) {
      callback(null, 'Country: ' + JSON.parse(body).value);
    });
  },

  function(callback) {
    request.get(url + 'getUserAge?id=1234', function(err, res, body) {
      callback(null, 'Age: ' + JSON.parse(body).value);
    });
  }

],

  function(err, results) {
    for (var i=0; i &lt; results.length; i++) {
      console.log(results[i]);
    }
  }

);
</code></pre>

<p>In case that one of the series steps passes a non-null value to its callback as the
first parameter, the series is immediately stopped, and the final callback is
triggered with the results that have been collected to far, and the <em>err</em> parameter
set to the error value passed by the failing step.</p>

<p><em>async.waterfall</em> is similar to <em>async.series</em>, as it executes all steps in series,
but it also enables us to access the results of a previous step in the step that
follows:</p>

<pre><code>'use strict';

var request = require('request');
var async = require('async');

var url = 'http://localhost:8080/';

async.waterfall([

    function(callback) {
      request.get(url + 'getSessionId', function(err, res, body) {
        callback(null, JSON.parse(body).value);
      });
    },

    function(sId, callback) {
      request.get(url + 'getUserId?sessionId=' + sId, function(err, res, body) {
        callback(null, sId, JSON.parse(body).value);
      });
    },

    function(sId, uId, callback) {
      request.get(url + 'getUserName?userId=' + uId, function(err, res, body) {
        callback(null, JSON.parse(body).value, sId);
      });
    }

  ],

  function(err, name, sId) {
    console.log('Name:', name);
    console.log('SessionID:', sId);
  }

);
</code></pre>

<p>Note how for each step function, <em>callback</em> is passed as the last argument. It
follows a list of arguments for each parameter that is passed by the previous
function, minus the error argument which each step function always passes as the first
parameter to the callback function.</p>

<p>Also note the difference in the final callback: instead of <em>results</em>, it too expects a
list of result values, passed by the last waterfall step.</p>

<p><em>async</em> provides several other interesting methods which help us to bring order in our
control flow and allows us to orchestrate tasks in an efficient manner. Check out
<a href="http://caolan.github.io/async/">the async documentation</a> for more details.</p>

<hr />

<p>This post is a chapter from <strong>The Node Craftsman Book</strong>, a comprehensive eBook which teaches
all aspects of real-world application building with Node.js, for example:</p>

<ul>
<li>Working with NPM and Packages</li>
<li><a class="internal" href="https://www.nodebeginner.org/">Object-oriented JavaScript</a></li>
<li>Test-Driven Node.js Development</li>
<li>Synchronous and Asynchronous operations explained</li>
<li>Using and creating Event Emitters</li>
<li>Node.js and MySQL</li>
<li>Node.js and MongoDB</li>
<li>Writing fast and efficient code</li>
<li><a class="internal" href="https://www.nodebeginner.org/">Writing a REST webservice application</a></li>
<li>Combining Node.js and AngularJS</li>
<li>Setting up a continuous deployment workflow</li>
</ul>

<p>It comes bundled with and extends <strong>The Node Beginner Book</strong>, <a href="https://www.nodebeginner.org">an introductionary tutorial
to Node.js development</a>, and both books together are <a href="https://leanpub.com/b/node-beginner-and-craftsman-bundle/">available from Leanpub for only $9.00</a>.</p>
          </div>
        </div>
        <div class="pagination">
          
            <a class="btn next " href="https://www.nodebeginner.org/blog/post/nodejs-tutorial-what-are-node.js-modules/">Next</a>
          
          
            <a class="btn previous " href="https://www.nodebeginner.org/blog/post/nodejs-tutorial-whatwg-url-parser/">Prev</a>
          
        </div>
      </div>
    </div>
    
    <div class="footer">
  
  <p>Copyright (c) 2017 Manuel Kiessling</p>
  
</div>

  </div>
  <script src="https://www.nodebeginner.org/blog/js/slim.js"></script>
  <script src="https://www.nodebeginner.org/blog/js/highlight.min.js"></script>
  <script>
    hljs.initHighlightingOnLoad();
  </script>
  <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-2127388-6', 'auto');
ga('send', 'pageview');

</script>

</body>

</html>
